﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ThreadQuery
{
    public class ProcessInfo
    {
        public int Total { get; set; }
        public int Current { get; set; }
        public string CommandName { get; set; }
    }

    public class ThreadParam
    {
        public List<string> TestData { get; set; }
        public int UnitCount { get; set; }
        public int CurrentThread { get; set; }
    }

    delegate string QueryDelegate(string postData);

    public class QueryProcess
    {
        int threadCount, queryCount;
        int current;
        string commandName;
        bool isBlock;
        private static object lockObject = new object();

        public QueryProcess(string commandName,int threadCount,int queryCount, bool isBlock)
        {
            current = 0;
            this.threadCount = threadCount;
            this.queryCount = queryCount;
            this.commandName = commandName;
            this.isBlock = isBlock;
        }

        public event EventHandler<EventArgs<string>> NewLog = null;
        public event EventHandler<EventArgs> Completed = null;
        public event EventHandler<EventArgs<ProcessInfo>> ProcessChanged = null;

        public void Exec()
        {
            int per = queryCount / threadCount;
            List<string> testData = getTestData(queryCount);

            Thread dedicatedThread;
            ThreadParam threadParam = null;
            for (int i = 0; i < threadCount; i++)
            {
                threadParam = new ThreadParam
                {
                    TestData = testData,
                    UnitCount = per,
                    CurrentThread = i
                };
                dedicatedThread = new Thread(ThreadWorker);
                dedicatedThread.Start(threadParam);
                //startThread(testData, per, i);
            }

        }

        public void ThreadWorker(Object thParam)
        {
            ThreadParam threadParam = (ThreadParam)thParam;
            startThread(threadParam.TestData, threadParam.UnitCount, threadParam.CurrentThread);
        }

        public void startThread(List<string> testData, int per, int currentThread)
        {
            QueryDelegate myDelegate = new QueryDelegate(Post);
            // 拆分
            for (int i = per * currentThread; i < per * currentThread + per; i++)
            {
                if (isBlock)
                {
                    // 阻塞
                    IAsyncResult result = myDelegate.BeginInvoke(testData[i], null, null);

                    QueryCompleted(result);
                }
                else
                {
                    myDelegate.BeginInvoke(testData[i], new AsyncCallback(QueryCompleted), null);
                }
            }
        }

        // 这里是实际的post请求
        public string Post(string jsonData)
        {
            // todo
            Thread.Sleep(1000);

            return jsonData;
        }

        public void QueryCompleted(IAsyncResult result)
        {
            AsyncResult _result = (AsyncResult)result;
            QueryDelegate myDelegate = (QueryDelegate)_result.AsyncDelegate;
            string data = myDelegate.EndInvoke(_result);
            string response = (string)result.AsyncState;
            string message = "ServerResponse: " + current + " " + data + "\r\n";

            lock (lockObject)
            {
                current++;
            }

            OnNewLog(message);
            OnProcessChanged();
            if (current == queryCount)
            {
                OnCompleted();
            }
        }

        public void OnProcessChanged()
        {
            if (ProcessChanged != null)
            { 
              ProcessChanged(this,new EventArgs<ProcessInfo>(new ProcessInfo(){ Current=current, Total=queryCount, CommandName=commandName}));
            }
        }

        public void OnCompleted()
        {
            if (Completed != null)
            {
                Completed(this, new EventArgs());
            }
        }

        public void OnNewLog(string text)
        {
            //WriteLog(text);
            if (NewLog != null)
            {
                NewLog(this, new EventArgs<string>(text));
            }
        }

        public List<string> getTestData(int count)
        {
            List<string> list = new List<string>(count);

            while (count > 0)
            {
                list.Add("test_" + count);
                count--;
            }

            return list;
        }
    }
}
